package cc.telecomdigital.tdstock.Http.Services;

import java.io.IOException;
import java.io.InputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import android.content.Context;
import android.util.Log;
import cc.telecomdigital.tdstock.Framework.UniqueItem.TDStockLog;
import cc.telecomdigital.tdstock.Services.LS_ClientParamMemory;

/**
 * Send http request template
 * @author ouyangzhihui
 *
 */
public abstract class H_SendTemplate
{
	static protected boolean	debugMode	= false;

	public interface IH_GatewayResult
	{
		void SetGateWayStatus(String iMStatusCode, String iMErrorMsg);
	}

	static protected final String[][]	internalError	=
	{
		{"0", 	"沒有錯誤。"},
		{"200", "沒有錯誤。"},
	    {"1",	"尚未連接數據網絡。" },
	    {"-11", "請求連接超時。"},
	    {"-12", "網絡連接超時。"},
	    {"404", "服務請求異常。"},
	    {"-1",	"會話已超時。"},
	    {"-2",  "網絡連接異常。"},
	    {"-3",	"系統繁忙。請稍後再試"},
	    {"-4",	"不知明的錯誤。"},
		{"-6",	"未有資料提供。" }, 
		{"-7",	"連線錯誤。" },
		{"-8",	"連線錯誤。" },
	};

	/**
	 * Inner error translation
	 * 
	 * @param iError
	 *            - this and child API defined error
	 * @param iIsChinese
	 *            - language to be used
	 * @return a non-null string
	 */
	static public String GetInnerErrorMessage(String iError)
	{
		int index, count;
		count = internalError.length;
		for (index = 0; index < count; index++)
		{
			if (iError.equals(internalError[index][0]) == false) continue;
			return internalError[index][1];
		}
		return "";
	}

	static protected final String	httpProtocolAgent	= "Android app/1.0.0";

	// For communication
	static protected final int		trialMax			= 50;
	static protected final int		sessionTrialMax		= 50;
	static protected final int		RETRY_DELAY_TIME	= 300;
	static protected final int		SOCKET_TIMEOUT		= 60000;
	static protected final int		CONNECT_TIMEOUT		= 60000;
	static private HttpClient		JCRequestClient		= null;

	static protected Object			httpLock			= new Object();
	static protected Object			logonLock			= new Object();

	protected Context				callerContext;
	
	protected String				accountNum, sessionKey;
	
	private String					className			= null;

	protected String GetIdentity()
	{
		if (className == null)
			className = getClass().getName();

		return className;
	}
	
	private String UrlToFormater(String urlTo)
	{
		urlTo = urlTo.replace("#FromServer#", LS_ClientParamMemory.GetWebServerInfo()).replace("#AccountNumber#", accountNum).replace("#TokenKey#", sessionKey);
		urlTo += "&app_type=0";
		
		if (debugMode)
			TDStockLog.i("HttpServiceRequest", "URL=>SessionKey: " + accountNum+","+sessionKey);
		
		if (debugMode)
		{
			TDStockLog.i(GetIdentity(), "UrlToString: " + urlTo);
		}
		return urlTo;
	}

	/** Get the HttpGet with content fill in **/
	protected HttpGet GetHttpGet(String urlTo)
	{
		HttpGet nextGet;
		nextGet = new HttpGet(UrlToFormater(urlTo));
		return nextGet;
	}

	/**
	 * Convert the InputStream into input source and ready for a byte stream
	 * conversion
	 **/
//	private InputSource ConvertToInputStream(InputStream iStreamer) throws IOException
//	{
//		String bufferLine, rrLine;
//		BufferedReader cReader;
//
//		// Read the data as String
//		bufferLine = "";
//		cReader = new BufferedReader(new InputStreamReader(iStreamer));
//
//		bufferLine = cReader.readLine();
//		TDStockLog.d("HttpServiceRequest", "start....");
//		int index = 0;
//		while ((rrLine = cReader.readLine()) != null)
//		{
//			bufferLine += rrLine;
//			index++;
//			TDStockLog.d("HttpServiceRequest", "...."+index);
//		}
//		TDStockLog.d("HttpServiceRequest", "end....");
//
//		if (debugMode)
//			Log.i(GetIdentity(), "ConvertToInputStream=>Content: " + bufferLine);
//
//		if ((bufferLine != null) && (bufferLine.length() != 0))
//		{
//			ByteArrayInputStream arrayStreamer;
//
//			arrayStreamer = new ByteArrayInputStream(bufferLine.getBytes("utf-8"));
//			// Try to be a gc helper
//			bufferLine = null;
//			return new InputSource(arrayStreamer);
//		}
//
//		return null;
//	}

	/** With inputStream, a return a possible valid Document of XML **/
	protected Document GetXmlFormatData(InputStream iStreamer)
	{
		Document doc;
		doc = null;
		try
		{
			DocumentBuilderFactory docFactory;
			DocumentBuilder docBuilder;
//			InputSource inSource;
//			inSource = ConvertToInputStream(iStreamer);

			docFactory = DocumentBuilderFactory.newInstance();
			docFactory.setIgnoringComments(true);
			docFactory.setIgnoringElementContentWhitespace(true);
			// docFactory.setValidating(false);
			docBuilder = docFactory.newDocumentBuilder();

//			doc = docBuilder.parse(inSource);
			doc = docBuilder.parse(iStreamer);
			doc.normalize();
		}
		catch (ParserConfigurationException e)
		{
			Log.e(GetIdentity(), "GetXmlFormateDate=>ParserConfigurationException: " + e.toString());
			e.printStackTrace();
			doc = null;
		}
		catch (SAXException e)
		{
			Log.e(GetIdentity(), "GetXmlFormateDate=>SAXException: " + e.toString());
			e.printStackTrace();
			doc = null;
		}
		catch (IOException e)
		{
			Log.e(GetIdentity(), "GetXmlFormateDate=>IOException: " + e.toString());
			e.printStackTrace();
			doc = null;
		}
		return doc;
	}

	/**
	 * If the getting client, keep providing weird result, reset this to get a
	 * new one when call
	 **/
	protected void ResetClient()
	{
		JCRequestClient = null;
	}

	/**
	 * Making our own http client, with the pre-defined port that all JC
	 * communication to be shared with
	 * 
	 * @return check for null or not to have the client
	 **/
	protected HttpClient GetDefaultHttpClient()
	{
		if (JCRequestClient != null)
			return JCRequestClient;

//		// HttpClient
//		DefaultHttpClient client = new DefaultHttpClient();
//		// HttpParams
//		HttpParams httpParams = client.getParams();
//		HttpConnectionParams.setConnectionTimeout(httpParams, CONNECT_TIMEOUT);
//		HttpConnectionParams.setSoTimeout(httpParams, SOCKET_TIMEOUT);
//		client.setParams(httpParams);
//		JCRequestClient = client;

		// Set basic data
		HttpParams params = new BasicHttpParams();

		// Set timeout
		HttpConnectionParams.setStaleCheckingEnabled(params, false);
		HttpConnectionParams.setConnectionTimeout(params, CONNECT_TIMEOUT);
		HttpConnectionParams.setSoTimeout(params, SOCKET_TIMEOUT);

		// I remember smart-tone could accept 1_0 only
		HttpProtocolParams.setContentCharset(params, "UTF-8");
		HttpProtocolParams.setUseExpectContinue(params, true);
		HttpProtocolParams.setUserAgent(params, httpProtocolAgent);

		// Some client params
		HttpClientParams.setRedirecting(params, false);

		// Register http/s shemas!
		SchemeRegistry schReg = new SchemeRegistry();
		schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));

		ClientConnectionManager conMgr;

		conMgr = new ThreadSafeClientConnManager(params, schReg);
		JCRequestClient = new DefaultHttpClient(conMgr, params);

		return JCRequestClient;
	}

	protected IH_GatewayResult H_SessionInfoParser(Element iFocusElement, IH_GatewayResult iReqResult)
	{
		String errorStatus, errorMessage;

		errorStatus = GetSingleElementValue(iFocusElement, "Status");
		errorMessage = GetSingleElementValue(iFocusElement, "ErrorMessage");
		
		if (debugMode)
			TDStockLog.i("HttpServiceRequest", "Session Error: "+errorStatus+","+errorMessage);
		
//		if(debugMode)
//			TDStockLog.i(GetIdentity(), "Session error: "+errorStatus+","+errorMessage);
		
		if (errorStatus.equals("0") == false)
		{
			errorStatus = "-1";
			errorMessage = GetInnerErrorMessage(errorStatus);
		}

		iReqResult.SetGateWayStatus(errorStatus, errorMessage);

		return iReqResult;
	}
	
	/**
	 * 
	 * @param iFocusElement
	 * @param iReqResult
	 * @return
	 */
	protected IH_GatewayResult H_GatewayInfoParser(Element iFocusElement, IH_GatewayResult iReqResult)
	{
		String errorStatus, errorMessage;

		errorStatus = GetSingleElementValue(iFocusElement, "Status").trim();
		errorMessage = GetSingleElementValue(iFocusElement, "ErrorMessage").trim();
		
		if(debugMode)
			TDStockLog.i("HttpServiceRequest", "Server data content error: "+errorStatus+","+errorMessage);
		
		if (errorStatus.equals(""))
		{
			errorStatus = "0";
			errorMessage = GetInnerErrorMessage(errorStatus);
		}
		
		if (!errorStatus.equals("0"))
		{
			errorStatus = "-8";
			errorMessage = GetInnerErrorMessage(errorStatus);
		}

		iReqResult.SetGateWayStatus(errorStatus, errorMessage);

		return iReqResult;
	}

	protected String GetSingleElementValue(Element iElement, String iTitle)
	{
		NodeList readList;
		Element readElement;

		try
		{
			readList = iElement.getElementsByTagName(iTitle);
			if ((readList == null) || (readList.getLength() <= 0))
				return "";

			readElement = (Element) readList.item(0);
			if (readElement == null)
				return "";

			readList = readElement.getChildNodes();
			if ((readList == null) || (readList.item(0) == null))
				return "";

			return readList.item(0).getNodeValue();
		}
		catch (Exception e)
		{
			Log.e(GetIdentity(), "GetSingleElementValue: " + e.toString());
		}

		return "";
	}

	protected H_SendTemplate(Context iCaller)
	{
		callerContext = iCaller;
		accountNum = "";
		sessionKey = "";
		JCRequestClient = null;
	}

	/**
	 * Set Account Information for the next Sending
	 * 
	 * @param iAccountNum
	 *            - AccountNumber from HttpAppInfo
	 * @param iSessionKey
	 *            - SessionKey from HttpAppInfo
	 */
	public void SetAccountInformation(String iAccountNum, String iSessionKey)
	{
		accountNum = iAccountNum;
		sessionKey = iSessionKey;
	}
	
}
